package org.budo.support.lang.util;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.safety.Whitelist;

/**
 * 适用于富文本的 XSS 过滤工具
 */
public class RichTextXssUtil {
    private final static Document.OutputSettings mOutputSettingsWithNoPrettyPrint = new Document.OutputSettings().prettyPrint(false);

    private RichTextXssUtil() {}

    public static String clean(String bodyHtml) {
        return clean(bodyHtml, MyWhitelist.customize(), mOutputSettingsWithNoPrettyPrint);
    }

    public static String clean(String bodyHtml, Whitelist useWhiteList, Document.OutputSettings outputSettings) {
        if (StringUtil.isEmptyOrNullString(bodyHtml)) {
            return bodyHtml;
        }
        return Jsoup.clean(bodyHtml, "", useWhiteList, outputSettings);
    }

    static class MyWhitelist extends Whitelist {

        public static MyWhitelist customize() {
            return (MyWhitelist) new MyWhitelist()//
                .addTags("a", "b", "blockquote", "br", "caption", "cite", "code", "col", //
                    "colgroup", "dd", "div", "dl", "dt", "em", "h1", "h2", "h3", "h4", //
                    "h5", "h6", "i", "img", "li", "ol", "p", "pre", "q", "small", "span", //
                    "strike", "strong", "sub", "sup", "table", "tbody", "td", "tfoot", "th", //
                    "thead", "tr", "u", "ul", "video", "source", "object", "param")//
                .addAttributes("a", "href", "title")//
                .addAttributes("blockquote", "cite")//
                .addAttributes("col", "span", "width")//
                .addAttributes("colgroup", "span", "width")//
                .addAttributes("img", "align", "alt", "height", "src", "title", "width")//
                .addAttributes("ol", "start", "type")//
                .addAttributes("q", "cite")//
                .addAttributes("table", "summary", "width")//
                .addAttributes("td", "abbr", "axis", "colspan", "rowspan", "width")//
                .addAttributes("th", "abbr", "axis", "colspan", "rowspan", "scope", "width")//
                .addAttributes("ul", "type")//
                .addAttributes("video", "autoplay", "controls", "height", "width", "loop", "preload", "src")//
                .addAttributes("source", "src", "type")//
                .addAttributes("object", "align", "archive", "border", "classid", "codebase", "codetype", "data", "declare", "form", "height", "hspace", "name", "standby", "type", "usemap", "vspace", "width")//
                .addAttributes("param", "name", "value", "valuetype", "type")//
                .addAttributes(":all", "style", "class", "id", "title", "translate", "lang", "hidden", "dir")//
                .preserveRelativeLinks(true);
        }

        private final static String[] mUnsafeAttributePrefixValue = { //
            "javascript:", //
            "data:text/html", //
            "data:text/javascript"//
        };

        @Override
        protected boolean isSafeAttribute(String tagName, Element el, Attribute attr) {
            if (super.isSafeAttribute(tagName, el, attr)) {
                final String attrValue = attr.getValue() != null ? //
                    attr.getValue().toLowerCase().trim().replaceAll("\\s*", "") : null;
                if (null == attrValue || attrValue.length() == 0) {
                    return true;
                }

                for (String unsafeAttributePrefixValue : mUnsafeAttributePrefixValue) {
                    if (attrValue.startsWith(unsafeAttributePrefixValue)) {
                        return false;
                    }
                }
                return true;
            }
            return false;
        }
    }
}
